package BD;

import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import org.apache.log4j.Logger;

public class MySql<T> {

    public LogsMySql log;
    private String user;
    private String pw;
    private String dataBaseName;
    private String host;
    private String url;
    private String Driver = "com.mysql.jdbc.Driver";
    private Connection conexion = null;
    private Statement sentencia = null;
    private CargarConfig cCfg;
    private static Logger logger = Logger.getLogger(MySql.class);

    public MySql() {
        log = new LogsMySql();

        cCfg = new CargarConfig();
        ConfiguracionMySql cfg = cCfg.LeerArchivo();

        try {
            this.user = cfg.getUser();
            pw = cfg.getPw();
            dataBaseName = cfg.getDataBaseName();
            host = cfg.getHost();
        } catch (NullPointerException e) {
            logger.error("Archivo de configuracion no encontrado", e);
            throw new MyException("Archivo de configuracion no encontrado", e);
        }
        url = "jdbc:mysql://" + host + "/" + dataBaseName;
    }

    public List<T> executeQuery(String sql, Class clase) {
        List<T> listaDeObjetos = new ArrayList<>();
        try {
            ResultSet filas;
            Class.forName(Driver);
            conexion = DriverManager.getConnection(url, user, pw);
            sentencia = conexion.createStatement();
            filas = sentencia.executeQuery(sql);//obtiene el resultset de la consulta

            while (filas.next()) {
                T objeto = (T) Class.forName(clase.getName()).newInstance(); //crea un objeto correspondiente a su clase
                Method[] metodos = objeto.getClass().getDeclaredMethods();//instancia todos los metodos de la clase
                for (int i = 0; i < metodos.length; i++) {
                    if (metodos[i].getName().startsWith("set")) {//si el metodo es un set->
                        metodos[i].invoke(objeto, filas.getObject(metodos[i].getName().substring(3)));
                        //metodos[i].getName().substring(3)) da el nombre de la columna en la BD
                        //se invoca el metodo set, pasandole como atributo el valor del resultset
                    }
                }
                listaDeObjetos.add(objeto);
            }

            filas.close();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | SecurityException | IllegalArgumentException | InvocationTargetException | SQLException e) {
            logger.error("Error al seleccionar registros", e);
            throw new MyException("Error al seleccionar registros", e);
        } finally {
            if (sentencia != null) {
                try {
                    sentencia.close();
                } catch (SQLException e) {
                    logger.error("Error al cerrar sentencia", e);
                    throw new MyException("Error de SQL", e);
                }
            }
            if (conexion != null) {
                try {
                    conexion.close();
                } catch (SQLException e) {
                    logger.error("Error al cerrar conexion", e);
                    throw new MyException("Error de SQL", e);
                }
            }
        }
        return listaDeObjetos;
    }

    /**
     *
     * @param sql Modifica, elimina o crea una sentencia sql pasada por
     * parametro
     * @return 0 si no sucedio el evento, != 0 si sucedio
     */
    public int executeUpdate(String sql) {

        int filasAfectadas = 0;
        try {
            Class.forName(Driver);
            conexion = DriverManager.getConnection(url, user, pw);
            sentencia = conexion.createStatement();
            filasAfectadas = sentencia.executeUpdate(sql);
        } catch (ClassNotFoundException e) {
            logger.error("Error driver", e);
            throw new MyException("Error driver", e);
        } catch (SQLException e) {
            logger.error("Error de SQL", e);
            throw new MyException("Error de SQL", e);
        } finally {
            if (sentencia != null) {
                try {
                    sentencia.close();
                } catch (SQLException e) {
                    logger.error("Error al cerrar sentencia", e);
                    throw new MyException("Error de SQL", e);
                }
            }
            if (conexion != null) {
                try {
                    conexion.close();
                } catch (SQLException e) {
                    logger.error("Error al cerrar conexion", e);
                    throw new MyException("Error de SQL", e);
                }
            }
        }
        return filasAfectadas;
    }
}
